<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <canvas id="canvas" width="600" height="400"></canvas>
    <script>
        ;(function(){
            const Easing = { Quadratic: { In: progress => progress * progress } }
            let ctx = null,         // 实例
                max = 0,            // 最大值
                min = 0,            // 最小值
                xScale = 0,         // x轴刻度
                yScale = 0,         // y轴刻度
                data = [],          // 数据
                space = 10,         // 标签与线的距离
                marginLeft = 50,    // 左侧距离
                marginTop = 50,     // 右侧距离
                marginBot = 50,     // 下边距离
                keyPoints = [],
                prevX = 0,
                prevY = 0,
                nextX = 0,
                nextY = 0,
                startTime = 0,
                duration = 1000,
                partProportion = 0,
                lineIndexCache = 1;
            
            function init() {
                const canvas = document.querySelector('#canvas');
                ctx = canvas.getContext('2d');
                readRatio();
            }
            function readRatio() {
                fetch('https://mock.mengxuegu.com/mock/62f719a8f2652f239bd0a7d1/ds/antvRatio').then( res => {
                    return res.json();
                }).then( res => {
                    const { data: { list } } = res;
                    let arr = list.reduce( (acc,item) => {
                        acc.push(item.value);
                        return acc;
                    },[]);
                    data = list;
                    max = Math.max(...arr);
                    min = Math.min(...arr);
                    if (min > 0) min = 0;
                    if (max < 0 && min < 0) max = 0;
                    markYscale();
                    markXscale();
                    drawLabel(5);
                    drawPoint();
                })
            }
            function markYscale() {
                const { width, height } = canvas;
                yScale = (height - (marginBot + marginTop)) / (max - min);
            }
            function markXscale() {
                const { width, height } = canvas;
                xScale = (width - (marginLeft + space)) / (data.length - 1);
            }
            function drawLabel(lineNum) {
                const diff = (max - min) / (lineNum - 1);
                ctx.textBaseline = "middle";
			    ctx.strokeStyle = '#F4F5F6';
                for(let i = 0; i < lineNum; i++) {
                    let text = max - i * diff,
                        x = marginLeft - ctx.measureText(text).width,
                        y = (marginTop) + yScale * (max - text);
                    ctx.fillText(text, x, y);
                    drawLine(marginLeft + space, y, canvas.width, y);
                }
                console.log( max, min );
            }
            function drawPoint() {
                for(let i = 0; i < data.length; i++) {
                    let x = (marginLeft + space) + i * xScale,
                        y = marginTop + yScale * (max - data[i].value);
                    keyPoints[i] = { x, y };
                }
                prevX = keyPoints[0].x;
                prevY = keyPoints[0].y;
                partProportion = 1 / (keyPoints.length - 1);
                requestAnimationFrame(step)
            }
            function step(currentTime) {
                // 第一帧绘制时记录下开始的时间
                !startTime && (startTime = currentTime)
                // 已经过去的时间(ms)
                const timeElapsed = currentTime - startTime
                // 动画执行的进度 {0,1}
                let progress = Math.min(timeElapsed / duration, 1)
                // 加入二次方缓动函数
                progress = Easing.Quadratic.In(progress)
                // 描述当前所绘制的是第几段线段
                const lineIndex = Math.min(Math.floor(progress / partProportion) + 1, keyPoints.length - 1)
                //  当前线段的进度 {0,1}
                const partProgress = (progress - (lineIndex - 1) * partProportion) / partProportion
                console.log( prevY  );

                const draw = () => {
                    ctx.strokeStyle = 'orange';
                    ctx.beginPath()
                    ctx.moveTo(prevX, prevY)
                    // 当绘制下一段线段前,把上一段末尾缺失的部分补齐
                    if (lineIndex !== lineIndexCache) {
                        ctx.lineTo(keyPoints[lineIndex - 1].x, keyPoints[lineIndex - 1].y)
                        lineIndexCache = lineIndex
                    }
                    prevX = nextX = (keyPoints[lineIndex - 1].x + (keyPoints[lineIndex].x - keyPoints[lineIndex - 1].x) * partProgress);
                    prevY = nextY = (keyPoints[lineIndex - 1].y + (keyPoints[lineIndex].y - keyPoints[lineIndex - 1].y) * partProgress);
                    ctx.lineTo(nextX, nextY)
                    ctx.stroke()
                }
                draw();
                if (progress < 1) {
                    requestAnimationFrame(step)
                } else {
                    console.log('动画执行完毕')
                }
            }
            function drawBgColor() {
                ctx.lineTo((marginLeft + space) + (data.length - 1) * xScale, canvas.height);
                ctx.lineTo((marginLeft + space), canvas.height);
                var gradient = ctx.createLinearGradient(0, 0, 0, canvas.height);
                gradient.addColorStop(0, 'rgba(255,131,0,0.10)');
                gradient.addColorStop(1, 'rgba(255,131,0,0.00)');
                ctx.fillStyle = gradient;
                ctx.fill();
            }
            function drawLine(startX, startY, endX, endY) {
                ctx.save();
                ctx.lineWidth = 1;
                ctx.translate(0.5, 0.5);	// 解决1px下 线条粗细不一的情况
                ctx.beginPath();
                ctx.moveTo(startX, startY);
                ctx.lineTo(endX, endY);
                ctx.stroke();
                ctx.restore();
            }
            init();
        })();
    </script>
</body>
</html>